package com.summer.ioc.container.util;

import com.summer.ioc.bean.annotation.Autowired;
import com.summer.ioc.bean.annotation.LazyLoad;
import com.summer.ioc.bean.annotation.Scope;
import com.summer.ioc.bean.definition.BeanDefinition;
import com.summer.ioc.bean.definition.component.AbstractComponentBeanDefinition;
import com.summer.ioc.bean.definition.component.DefaultComponentBeanDefinition;
import com.summer.ioc.component.annotation.Component;
import com.summer.ioc.container.IocContainer;
import com.summer.ioc.exception.BeanException;
import com.summer.ioc.reflect.Parameter;
import com.summer.ioc.util.AnnotationUtil;
import com.summer.ioc.util.ClassUtil;
import com.summer.ioc.util.MethodUtil;
import com.summer.ioc.util.StringUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.List;

/**
 * @author xiaoye
 * @create 2021-05-12 23:37
 */
public class ComponentUtil {

    public static AbstractComponentBeanDefinition buildComponentBeanDefinition(Class componentClass)
    {
        if (!AnnotationUtil.isComponent(componentClass))
        {
            throw new BeanException("["+componentClass.getName()+"] 不是一个组件" );
        }
        String name = null;
        Component componentAnnotation = AnnotationUtil.getAnnotation(componentClass, Component.class);
        if (StringUtils.hasText(componentAnnotation.name()))
            name = componentAnnotation.name();
        name = StringUtils.firstLetterToLowerCase(componentClass.getSimpleName());
        var bd = new DefaultComponentBeanDefinition(name,componentClass);
        if (AnnotationUtil.existAnnotation(componentClass, Scope.class))
            bd.setScope(AnnotationUtil.getAnnotation(componentClass,Scope.class).value());
        if (AnnotationUtil.existAnnotation(componentClass, LazyLoad.class))
            bd.setLazyLoad(AnnotationUtil.getAnnotation(componentClass,LazyLoad.class).value());
        return bd;
    }

    public static Object buildComponentBean(BeanDefinition beanDefinition, IocContainer container) {
        Class beanClass = beanDefinition.getBeanClass();
        var constructor = beanClass.getConstructors()[0];
        int parameterCount = constructor.getParameterCount();
        Object bean = null;
        try{
            if (parameterCount == 0)
                bean = constructor.newInstance();
            else
            {
                Object[] params = buildParameters(constructor, container);
                bean = constructor.newInstance(params);
            }
            Field[] declaredFields = beanClass.getDeclaredFields();
            for (Field field : declaredFields) {
                if (AnnotationUtil.existAnnotation(field,Autowired.class))
                    field.set(bean,container.getBean(field.getName()));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return bean;
    }

    private static Object[] buildParameters(Constructor constructor,IocContainer container) {
        Parameter[] parameters = MethodUtil.getParameters(constructor);
        Object[] params = new Object[parameters.length];
        if (AnnotationUtil.existAnnotation(constructor, Autowired.class))
        {

            for (int i = 0; i < parameters.length; i++) {
                params[i] = container.getBean(parameters[i].getName());
            }
            return params;
        }
        else
        {
            for (int i = 0; i < parameters.length; i++) {
                if (AnnotationUtil.existAnnotation(parameters[i].getParameter(),Autowired.class))
                    params[i] = container.getBean(parameters[i].getName());
                else
                    params[i] = null;
            }

        }
        return params;
    }

    public static void scanComponent(String[] basePackages, IocContainer container)
    {
        List<Class<?>> classList = ClassUtil.getClassesByPackageNames(basePackages);
        for (Class<?> componentClass : classList) {
            if (AnnotationUtil.isComponent(componentClass))
            {
                var bd = ComponentUtil.buildComponentBeanDefinition(componentClass);;
                container.registryBean(bd);
            }
        }
    }


}
